package main

import (
	"bytes"
	"fmt"
	"net/http"
	"sync"
	"time"

	"github.com/valyala/fasthttp"
)

type counter struct {
	mu              sync.RWMutex //单写多读模型，读锁占用情况下会阻止写但不会阻止读
	Durations       map[Status]int64
	Counts          map[Status]int64
	RoutedCounts    map[Status]int64
	RoutedDurations map[Status]int64
}

func NewCounter() *counter { //New初始化
	return &counter{
		Durations:       make(map[Status]int64),
		Counts:          make(map[Status]int64),
		RoutedCounts:    make(map[Status]int64),
		RoutedDurations: make(map[Status]int64),
	}
}

type Status struct {
	IsForced   bool // call only
	IsFallback bool // call only
	IsNull     bool // call only
	Address    string
	Code       int
	Err        error //routed call only
}

func (c *counter) Handler(ctx *fasthttp.RequestCtx) {
	if !ctx.Request.Header.IsGet() { //如果没有得到请求
		ctx.Response.Header.SetStatusCode(http.StatusNotFound) //所有找不到都设置成404
	}
	//LOG.Infof("prometheus's path=====>", string(ctx.Request.URI().Path()))
	switch string(ctx.Request.URI().Path()) {
	case "/prome":
		fmt.Fprintf(ctx, "%s", c.prome())
		//Fprintf(w io.Writer, format string, a ...interface{});%q 字符串安全转义
		//%s 输出字符串表示（string类型或[]byte),这里q需要改为s
	default:
		ctx.Response.Header.SetStatusCode(http.StatusNotFound) //默认都设置为404
	}
}

func (c *counter) prome() []byte { //四个里面是封装isFallback等这些状态。
	buf := new(bytes.Buffer)
	c.mu.RLock() //多个goroutine可同时获取读锁
	defer c.mu.RUnlock()

	buf.WriteString(fmt.Sprintf("# TYPE request_count counter\n"))
	//func (b *Buffer) WriteString(s string，写入s) (n int长度, err error)
	//(Sprintf(format string, a ...interface{}) string) formats according to a format specifier and returns the resulting string.

	for k, v := range c.Counts {
		s := fmt.Sprintf("request_count{code=\"%d\",fallback=\"%v\",forced=\"%v\",null=\"%v\",} %d %d000\n",
			k.Code, k.IsFallback, k.IsForced, k.IsNull, v, time.Now().Unix())
		buf.WriteString(s)
	}
	buf.WriteString(fmt.Sprintf("# TYPE request_duration counter\n"))
	for k, v := range c.Durations {
		s := fmt.Sprintf("request_duration{code=\"%d\",fallback=\"%v\",forced=\"%v\",null=\"%v\",} %d %d000\n",
			k.Code, k.IsFallback, k.IsForced, k.IsNull, v, time.Now().Unix())
		buf.WriteString(s)
	}
	buf.WriteString(fmt.Sprintf("# TYPE routed_request_count counter\n"))
	for k, v := range c.RoutedCounts {
		s := fmt.Sprintf("routed_request_count{code=\"%d\",addr=\"%s\",err=\"%v\",} %d %d000\n",
			k.Code, k.Address, k.Err, v, time.Now().Unix()) //这个v跟上面的counts一样；不一定一样了，有多个请求
		buf.WriteString(s)
	}
	buf.WriteString(fmt.Sprintf("# TYPE routed_request_duration counter\n"))
	for k, v := range c.RoutedDurations {
		s := fmt.Sprintf("routed_request_duration{code=\"%d\",addr=\"%s\",err=\"%v\",} %d %d000\n",
			k.Code, k.Address, k.Err, v, time.Now().Unix()) //这里不能使用err.error(),否则会指针错误
		buf.WriteString(s)
	}
	return buf.Bytes() //返回字节
}

func (c *counter) call(req *http.Request, do func(*http.Request) (*http.Response, error)) (*http.Response, error) {
	t := time.Now()
	resp, err := do(req) //req，得到resp-->这个就是在GetAddress中重新NewReques后来这里请求的
	t1 := time.Since(t)
	duration := t1.Nanoseconds() / 1000 / 1000

	if err != nil {
		return nil, err
		//	resp.Body.Close()
	}
	key := Status{
		Address: req.Host,        //得到req
		Code:    resp.StatusCode, //resp得到响应的状态吗
		Err:     err,
	}
	//defer resp.Body.Close()

	c.mu.Lock()         //写锁定
	defer c.mu.Unlock() //写解锁
	LOG.Infof("handled %s , duration: %d (ms), status: %+v \n", req.URL.String(), duration, key)

	c.RoutedCounts[key] += 1
	c.RoutedDurations[key] += duration
	return resp, err
}

func (c *counter) Call(ctx *fasthttp.RequestCtx, handle func(*fasthttp.RequestCtx) Status) {
	t := time.Now()
	status := handle(ctx)
	t1 := time.Since(t)
	duration := t1.Nanoseconds() / 1000 / 1000

	LOG.Infof("[%d] handled , duration: %d (ms), status: %+v \n", ctx.ConnID(), duration, status)
	c.mu.Lock()
	defer c.mu.Unlock()
	c.Durations[status] += duration
	c.Counts[status] += 1
}
